﻿using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Xml.Serialization;

namespace Samurai.Wakizashi.Extensions
{
    public static class ObjectExtensions
    {
        /// <summary>
        /// Creates an xml serialized version of the object.
        /// </summary>
        /// <param name="o">The o.</param>
        /// <returns></returns>
        public static string ToXml(this object o)
        {
            return ToXml(o, string.Empty);
        }

        /// <summary>
        /// Creates an xml serialized version of the object.
        /// </summary>
        /// <param name="o">The o.</param>
        /// <param name="defaultNamespace">The default namespace.</param>
        /// <returns></returns>
        public static string ToXml(this object o, string defaultNamespace)
        {
            var serializer = new XmlSerializer(o.GetType(), defaultNamespace);
            using (var writer = new StringWriter())
            {

                serializer.Serialize(writer, o, null);

                return writer.ToString();
            }
        }

        /// <summary>
        /// Creates a binary serialized version of this instance.
        /// </summary>
        /// <returns>Byte array containing the serialized object.</returns>
        public static byte[] ToBytes(this object o)
        {
            using (var ms = new MemoryStream())
            {
                var formatter = new BinaryFormatter();
                formatter.Serialize(ms, o);

                var bytes = new byte[ms.Length];
                ms.Read(bytes, 0, (int)ms.Length);

                return bytes;
            }
        }

        /// <summary>
        ///  Deserializes an object from xml and returns the instance.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <param name="xml">The XML.</param>
        /// <returns></returns>
        public static object FromXml(Type type, string xml)
        {
            return FromXml(type, xml, null);
        }

        /// <summary>
        /// Deserializes an object from xml and returns the instance.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <param name="xml">The XML.</param>
        /// <param name="defaultNamespace">The default namespace.</param>
        /// <returns></returns>
        public static object FromXml(Type type, string xml, string defaultNamespace)
        {
            var serializer = new XmlSerializer(type, defaultNamespace);
            using (var reader = new StringReader(xml))
            {
                return serializer.Deserialize(reader);
            }
        }

        /// <summary>
        /// Deserializes an object from xml and returns the instance.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="xml">The XML.</param>
        /// <returns></returns>
        public static T FromXml<T>(string xml) where T : class
        {
            return FromXml<T>(xml, null);
        }

        /// <summary>
        /// Deserializes an object from xml and returns the instance.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="xml">The XML.</param>
        /// <param name="defaultNamespace">The default namespace.</param>
        /// <returns>Deserialized instance.</returns>
        public static T FromXml<T>(string xml, string defaultNamespace) where T : class
        {
            var serializer = new XmlSerializer(typeof(T), defaultNamespace);
            using (var reader = new StringReader(xml))
            {
                return (T)serializer.Deserialize(reader);
            }
        }

        /// <summary>
        /// Deserializes an object from a byte array and returns the instance.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <param name="bytes">The bytes.</param>
        /// <returns></returns>
        public static object FromBytes(Type type, byte[] bytes)
        {
            using (var ms = new MemoryStream())
            {
                ms.Write(bytes, 0, bytes.Length);
                var formatter = new BinaryFormatter();

                return formatter.Deserialize(ms);
            }
        }

        /// <summary>
        /// Deserializes an object from a byte array and returns the instance.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="bytes">The bytes.</param>
        /// <returns>Deserialized instance.</returns>
        public static T FromBytes<T>(byte[] bytes) where T : class
        {
            using (var ms = new MemoryStream())
            {
                ms.Write(bytes, 0, bytes.Length);
                var formatter = new BinaryFormatter();

                return (T)formatter.Deserialize(ms);
            }
        }
    }
}
